<!DOCTYPE html>
<html>
<head>
<title>Spring-Mass System</title>
<style>
  body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f0f0f0;
  }
  canvas {
    border: 1px solid #ccc;
    background-color: #fff;
  }
</style>
</head>
<body>
<canvas id="physicsCanvas" width="500" height="550"></canvas>
<script>
  const canvas = document.getElementById('physicsCanvas');
  const ctx = canvas.getContext('2d');

  // General drawing settings
  ctx.strokeStyle = 'black';
  ctx.fillStyle = 'black';
  ctx.lineWidth = 1.5;
  ctx.font = '16px Arial';
  ctx.textAlign = 'left';
  ctx.textBaseline = 'middle';

  // --- 1. Fixed Point ---
  const fixedX1 = 175;
  const fixedX2 = 325;
  const fixedY = 50;
  const attachX = 250;
  const attachY = 55;

  // Draw the fixed surface
  ctx.beginPath();
  ctx.moveTo(fixedX1, fixedY);
  ctx.lineTo(fixedX2, fixedY);
  ctx.stroke();

  // Draw hatching for the surface
  ctx.save();
  ctx.lineWidth = 1;
  for (let x = fixedX1; x <= fixedX2; x += 10) {
    ctx.beginPath();
    ctx.moveTo(x, fixedY);
    ctx.lineTo(x - 10, fixedY - 10);
    ctx.stroke();
  }
  ctx.restore();

  // Draw the attachment point
  ctx.beginPath();
  ctx.arc(attachX, attachY, 5, 0, 2 * Math.PI);
  ctx.fill();

  // --- 2. Spring ---
  const springCx = attachX;
  const springRx = 45;
  const springRy = 10;
  const numCoils = 8;
  const springTopY = attachY + 5;
  const springBottomY = springTopY + numCoils * 2 * springRy;

  ctx.beginPath();
  ctx.moveTo(springCx, attachY);
  ctx.lineTo(springCx, springTopY);

  // Draw the coils as a continuous path
  let currentY = springTopY;
  for (let i = 0; i < numCoils; i++) {
    const centerY = currentY + springRy;
    // Back part of the coil
    ctx.ellipse(springCx, centerY, springRx, springRy, 0, Math.PI, 0, true);
    // Front part of the coil
    ctx.ellipse(springCx, centerY, springRx, springRy, 0, 0, Math.PI, false);
    currentY += 2 * springRy;
  }

  // Connector to the object
  const objectHookY = springBottomY + 20;
  ctx.lineTo(springCx, objectHookY);
  ctx.stroke();


  // --- 3. Object ---
  const objectAttachY = objectHookY + 5;
  const objectTopY = objectAttachY + 5;
  const objectHeight = 50;
  const objectTopWidth = 70;
  const objectBottomWidth = 90;

  // Attachment ring on the object
  ctx.beginPath();
  ctx.arc(springCx, objectAttachY, 5, 0, 2 * Math.PI);
  ctx.stroke();

  // Trapezoid shape for the object
  const x1 = springCx - objectTopWidth / 2;
  const x2 = springCx + objectTopWidth / 2;
  const x3 = springCx + objectBottomWidth / 2;
  const x4 = springCx - objectBottomWidth / 2;
  const y1 = objectTopY;
  const y2 = objectTopY + objectHeight;

  ctx.beginPath();
  ctx.moveTo(x1, y1);
  ctx.lineTo(x2, y1);
  ctx.lineTo(x3, y2);
  ctx.lineTo(x4, y2);
  ctx.closePath();
  ctx.stroke();

  // --- 4. Equilibrium Position and Oscillations ---
  const equilibriumY = y1 + objectHeight / 2; // Center of the object in this depiction
  const oscillationArrowX = 400;

  // Draw Equilibrium Position line
  ctx.save();
  ctx.setLineDash([5, 5]);
  ctx.beginPath();
  ctx.moveTo(150, equilibriumY);
  ctx.lineTo(470, equilibriumY);
  ctx.stroke();
  ctx.restore();

  // Draw Oscillations arrow
  const arrowTopY = equilibriumY - 80;
  const arrowBottomY = equilibriumY + 80;
  
  // Arrow line
  ctx.beginPath();
  ctx.moveTo(oscillationArrowX, arrowTopY);
  ctx.lineTo(oscillationArrowX, arrowBottomY);
  ctx.stroke();
  
  // Helper function for arrowheads
  function drawArrowhead(ctx, x, y, angle) {
    const headlen = 10;
    ctx.save();
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x - headlen * Math.cos(angle - Math.PI / 6), y - headlen * Math.sin(angle - Math.PI / 6));
    ctx.moveTo(x, y);
    ctx.lineTo(x - headlen * Math.cos(angle + Math.PI / 6), y - headlen * Math.sin(angle + Math.PI / 6));
    ctx.stroke();
    ctx.restore();
  }
  
  // Draw top and bottom arrowheads
  drawArrowhead(ctx, oscillationArrowX, arrowTopY, -Math.PI / 2); // Up
  drawArrowhead(ctx, oscillationArrowX, arrowBottomY, Math.PI / 2); // Down

  // --- 5. Labels ---
  // "fixed point"
  ctx.fillText('fixed point', attachX + 15, attachY);
  
  // "spring"
  ctx.fillText('spring', 80, 150);
  ctx.beginPath();
  ctx.moveTo(128, 150);
  ctx.lineTo(200, 150);
  ctx.stroke();
  
  // "object"
  ctx.fillText('object', 120, objectTopY + 10);
  ctx.beginPath();
  ctx.moveTo(170, objectTopY + 10);
  ctx.lineTo(210, objectTopY + 10);
  ctx.stroke();
  
  // "oscillations"
  ctx.fillText('oscillations', oscillationArrowX + 15, equilibriumY);
  
  // "equilibrium position"
  ctx.fillText('equilibrium position', 280, equilibriumY + 15);

  // --- 6. Figure Caption ---
  ctx.textAlign = 'center';
  ctx.fillText('Fig. 3.1', canvas.width / 2, 500);

</script>
</body>
</html>